package com.yunkss.eftool.crypto.key;

import cn.hutool.core.util.HexUtil;
import com.yunkss.eftool.crypto.operator.EftoolSM2Operator;
import com.yunkss.eftool.crypto.params.ParameterCalculator;
import com.yunkss.eftool.crypto.params.SM2Parameters;
import com.yunkss.eftool.crypto.params.SmProvider;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.util.encoders.Hex;

import java.math.BigInteger;
import java.security.SecureRandom;

/**
 * @author csx
 * @date 2022/2/18 8:28
 * @desc
 */

public class SM2KeyGenerator extends SmProvider {
    public SM2KeyGenerator() {
    }

    public static UnCompresseSM2KeyPair generateUnzipSM2KeyPair() {
        AsymmetricCipherKeyPair keyPairParameter = generateKeyPairParameter();
        ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters) keyPairParameter.getPrivate();
        ECPublicKeyParameters pub = (ECPublicKeyParameters) keyPairParameter.getPublic();
        UnCompresseSM2KeyPair keypair = new UnCompresseSM2KeyPair();
        keypair.setPublicHexX(pub.getQ().getAffineXCoord().toBigInteger().toString(16));
        keypair.setPublicHexY(pub.getQ().getAffineYCoord().toBigInteger().toString(16));
        keypair.setPublicHex("04" + keypair.getPublicHexX() + keypair.getPublicHexY());
        keypair.setPrivateHex(privateKey.getD().toString(16));
        return keypair;
    }

    public static ECPrivateKeyParameters getSM2PrivateKey(String privateHex) {
        return new ECPrivateKeyParameters(new BigInteger(privateHex, 16), SM2Parameters.DOMAIN_PARAMS);
    }

    public static ECPublicKeyParameters getSM2PublicKey(String publicHex) {
        return new ECPublicKeyParameters(SM2Parameters.CURVE.decodePoint(Hex.decode(publicHex)), SM2Parameters.DOMAIN_PARAMS);
    }

    private static ECPublicKeyParameters getSM2PublicKey(String publicX, String publicY) {
        boolean marker = true;
        byte[] x = Hex.decode(publicX);
        byte[] y = Hex.decode(publicY);
        int curveSize = ParameterCalculator.getCurveLength(SM2Parameters.DOMAIN_PARAMS);
        x = ParameterCalculator.fixBytes(curveSize, x);
        y = ParameterCalculator.fixBytes(curveSize, y);
        byte[] encodedPubKey = new byte[1 + x.length + y.length];
        System.arraycopy(x, 0, encodedPubKey, 1, x.length);
        System.arraycopy(y, 0, encodedPubKey, 1 + x.length, y.length);
        return new ECPublicKeyParameters(SM2Parameters.CURVE.decodePoint(encodedPubKey), SM2Parameters.DOMAIN_PARAMS);
    }

    private static AsymmetricCipherKeyPair generateKeyPairParameter() {
        SecureRandom random = new SecureRandom();
        return generateKeyPairParameter(SM2Parameters.DOMAIN_PARAMS, random);
    }

    private static AsymmetricCipherKeyPair generateKeyPairParameter(ECDomainParameters domainParameters, SecureRandom random) {
        ECKeyGenerationParameters keyGenerationParams = new ECKeyGenerationParameters(domainParameters, random);
        ECKeyPairGenerator keyGen = new ECKeyPairGenerator();
        keyGen.init(keyGenerationParams);
        return keyGen.generateKeyPair();
    }

    public static void main(String[] args) throws InvalidCipherTextException {
        AsymmetricCipherKeyPair keyPair = SM2KeyGenerator.generateKeyPairParameter();
        ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters) keyPair.getPrivate();
        ECPublicKeyParameters publicKey = (ECPublicKeyParameters) keyPair.getPublic();
        String pri = privateKey.getD().toString(16);

        String pub = publicKey.getQ().getAffineXCoord().toBigInteger().toString(16);
        System.out.println(pri);

        String encrypt = new EftoolSM2Operator().encrypt("'测试加密'", pub);
        System.out.println(encrypt);
        String decrypt = new EftoolSM2Operator().decrypt(encrypt, pri);
        System.out.println(decrypt);
    }

}
